import { postGetallcertificates } from "@/apis/endpoint/home";
import { Cert } from "@/apis/endpoint/model";
import { postMyEdithonorcertificate } from "@/apis/endpoint/my";
import GpContainer from "@/components/GpContainer";
import GpFontIcon from "@/components/GpFontIcon";
import { GpSearchInput } from "@/components/GpSeachInput";
import GpVerticelLine from "@/components/GpVerticelLine";
import { withCache } from "@/utils/cache";
import { debounce, removeItem } from "@/utils/helper";
import { navigate } from "@/utils/navigation";
import { Popup, SafeArea } from "@taroify/core";
import { Button, ScrollView, Text, View } from "@tarojs/components";
import Taro, { useRouter } from "@tarojs/taro";
import clsx from "clsx";
import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useImmer } from "use-immer";

type CertificateEntry = Cert & {
  root?: {id: number; name: string}
  parent?: {id: number; name: string}
}
type CertificateGroup = Expandable<CertificateEntry>
type CertificateGroupMap = {
  [rid: number]: CertificateGroup
}

type SearchItem = {
  node: React.ReactNode
  item: CertificateEntry
}

type SelectPannelState = {
  open: boolean
  pannelSelects: Array<CertificateEntry>
  options: Array<Expandable<CertificateEntry>>
}

type RouteParams = {
  names?: string
}
export default function Index() {
  const router = useRouter<RouteParams>()
  const certificateNames = router.params.names ? router.params.names.split(",") : null
  const [rootNodes, setRootNodes] = useState<Cert[]>([])
  const availableCertificates = useRef<CertificateEntry[]>([])
  const certificateGroupMap = useRef<CertificateGroupMap>({})
  const [currentGroup, setCurrentGroup] = useState<CertificateGroup>()
  const [selects, setSelects] = useImmer<Array<CertificateEntry>>([])
  const [selectPannelState, setSelectPannelState] = useImmer<SelectPannelState>({
    open: false,
    options: [],
    pannelSelects: []
  })
  const selectSum = useMemo(() => {
    const sumMap: {[rid: number]: number} = {}
    selects.forEach(l => {
      const rid = l.root?.id || l.parent?.id
      sumMap[rid!] ??= 0
      sumMap[rid!]++
    })
    return sumMap
  }, [selects])
  const [search, setSearch] = useState("")
  const [searchList, setSearchList] = useState<SearchItem[]>([])
  const triggerSearch = useCallback(debounce(300, (value: string) => {
    const text = value.trim()
    if (text.length === 0) {
      setSearchList([])
      return;
    }
    const regEx = new RegExp(`(${text})`, "i");
    const nodes = availableCertificates.current
    .filter(item => regEx.test(item.name))
    .map(item => {
      const spliter = React.createElement(Text, {
        className: "text-theme"
      }, text)
      const parts = item.name.split(regEx).map<React.ReactNode>(part => {
        if (part === text) return spliter
        return part
      })
      return {
        node: parts,
        item
      }
    })
    setSearchList(nodes)
  }), [rootNodes])
  useEffect(() => {
    withCache("postGetallcertificates", () => postGetallcertificates().send())
    .then(list => {
      const roots: Cert[] = []
      const others: CertificateEntry[] = []
      list.forEach(item => {
        if (!item.parentId) {
          roots.push(item)
        } else {
          others.push(item)
        }
      })
      for (let i = 0; i < roots.length; i++) {
        const r = roots[i]
        certificateGroupMap.current[r.id] ??= {
          item: r,
          children: []
        }
        for (let j = 0; j < others.length; j++) {
          const p = others[j]
          if (p.parentId === r.id) {
            p.parent = { id: r.id, name: r.name }
            certificateGroupMap.current[r.id].children.push({
              item: p,
              children: []
            })
            others.splice(j, 1)
            j--
          }
        }
        for (let k = 0; k < certificateGroupMap.current[r.id].children.length; k++) {
          const p = certificateGroupMap.current[r.id].children[k]
          for (let t = 0; t < others.length; t++) {
            const l = others[t]
            if (l.parentId === p.item.id) {
              l.root = { id: r.id, name: r.name }
              l.parent = { id: p.item.id, name: p.item.name }
              p.children.push({
                item: l,
                children: []
              })
              others.splice(t, 1)
              t--
            }
          }
        }
      }
      const rootIds = Object.keys(certificateGroupMap.current)
      for (let i = 0; i < rootIds.length; i++) {
        const r = certificateGroupMap.current[rootIds[i]] as CertificateGroup
        for (let j = 0; j < r.children.length; j++) {
          const p = r.children[j]
          if (p.children.length) {
            p.children.forEach(l => {
              availableCertificates.current.push(l.item)
            })
          } else {
            availableCertificates.current.push(p.item)
          }
        }
      }
      if (certificateNames) {
        setSelects(certificateNames.map(name => availableCertificates.current.find(l => l.name === name)!))
      }
      setCurrentGroup(certificateGroupMap.current[roots[0].id])
      setRootNodes(roots)
    })
  }, [])
  function handleSearchChange(value: string) {
    setSearch(value)
    triggerSearch(value)
  }
  function handleTapItem(item: CertificateEntry) {
    if (~selects.findIndex(l => l.id === item.id)) {
      handleRemoveSelect(item)
    } else {
      setSelects(draft => {
        draft.push(item)
      })
    }
    handleSearchChange("")
  }
  function handleRemoveSelect(item: CertificateEntry) {
    setSelects(draft => {
      removeItem(draft, l => l.id === item.id)
    })
  }
  function hasSelects(entry: Expandable<CertificateEntry>) {
    if (entry.children.length) {
      return entry.children.some(l => selects.findIndex(m => m.id === l.item.id) !== -1)
    }
    return selects.findIndex(m => m.id === entry.item.id) !== -1
  }
  function handleTapEntry(entry: Expandable<CertificateEntry>) {
    if (entry.children.length) {
      setSelectPannelState({
        open: true,
        options: entry.children,
        pannelSelects: [...selects]
      })
    } else {
      handleTapItem(entry.item)
    }
  }
  function handleCloseSelectPannel() {
    setSelectPannelState({
      open: false,
      options: [],
      pannelSelects: []
    })
  }
  function handleTapPannelEntry(entry: Expandable<CertificateEntry>) {
    const { pannelSelects } = selectPannelState
    if (~pannelSelects.findIndex(l => l.id === entry.item.id)) {
      setSelectPannelState(draft => {
        removeItem(draft.pannelSelects, l => l.id === entry.item.id)
      })
    } else {
      setSelectPannelState(draft => {
        draft.pannelSelects.push(entry.item)
      })
    }
  }
  function handleSaveSelectPannel() {
    setSelects([...selectPannelState.pannelSelects])
    handleCloseSelectPannel()
  }
  async function handleSave() {
    process.env.NODE_ENV === "development" && console.log('选择了资格证书:', selects)
    const md = selects.map(l => `- ${l.name}`).join("\r\n")
    await postMyEdithonorcertificate(JSON.stringify(md)).send({ showLoading: true, loadingText: "保存中" })
    Taro.showToast({
      title: "保存成功",
      icon: "success"
    })
    navigate()
  }
  function renderCertificateList() {
    return (
      <Fragment>
        <View className="flex-1 h-0 box-border flex flex-row items-stretch">
          <View className="h-full w-[252px] flex-none bg-[#F4F6FC]">
            <ScrollView
              style={{height: "100%"}}
              scrollY
              scrollWithAnimation
            >
              {
                rootNodes.map(item => (
                  <View key={item.id} className={clsx("flex flex-row items-center relative box-border w-full h-[100px] pl-[32px] pr-[28px]", {
                    "bg-white": item.id === currentGroup?.item.id
                    })}
                    onClick={() => setCurrentGroup(certificateGroupMap.current[item.id])}
                  >
                    {
                      item.id === currentGroup?.item.id
                      ? <GpVerticelLine width={8} height={64} className="rounded-[4px] absolute left-0 my-auto" />
                      : null
                    }
                    <Text className={clsx("text-[28px]", item.id === currentGroup?.item.id ? "text-theme font-bold" : "text-primary font-normal")}>
                      {item.name}
                    </Text>
                    {
                      selectSum[item.id]
                      ? (
                        <View className="size-[32px] bg-theme rounded-[50%] flex justify-center items-center flex-none ml-[24px]">
                          <Text className="text-white text-[24px]">{selectSum[item.id]}</Text>
                        </View>
                      ) : null
                    }
                  </View>
                ))
              }
            </ScrollView>
          </View>
          <View className="h-full flex-1 w-0 bg-white">
            <ScrollView
              style={{height: "100%"}}
              scrollY
              scrollWithAnimation
            >
              <View className="box-border px-[32px]">
                <View className="grid grid-cols-1 gap-[18px]">
                  {
                    currentGroup?.children.map(l => (
                      <View key={l.item.id} onClick={() => handleTapEntry(l)}
                      className={clsx("flex flex-row justify-center items-center rounded-[16px] px-[20px] py-[24px] truncate", hasSelects(l) === false ? "bg-[#F4F6FC] text-primary" : "bg-theme text-white font-bold")}>
                        <Text className="text-[28px] text-center">
                          {l.item.name}
                        </Text>
                      </View>
                    ))
                  }
                </View>
              </View>
            </ScrollView>
          </View>
        </View>
        {renderSelects()}
      </Fragment>
    )
  }
  function renderSearchList() {
    return (
      <View className="box-border px-[32px] flex-1 h-0 overflow-y-auto">
        {
          searchList.map(item => (
            <View onClick={() => handleTapItem(item.item)} className="flex flex-col gap-[16px] justify-center h-[138px] text-primary text-[32px] border-b-2 border-solid border-b-[#EEEEEE]">
              <Text>{item.node}</Text>
              <Text className="text-third text-[24px]">{item.item.root?.name}-{item.item.parent?.name}-{item.item.name}</Text>
            </View>
          ))
        }
      </View>
    )
  }
  function renderSelects() {
    return (
      <View className="flex-none bg-white">
        <View className="flex flex-row items-stretch box-border h-[80px]">
          <Text className="flex-none pl-[32px] pr-[20px] text-secondary text-[28px] leading-[80px]">
            已选
          </Text>
          <ScrollView
            style={{width: 0, flex: 1, display: "flex", flexDirection: "row", alignItems: "center", gap: 16}}
            scrollX
            scrollWithAnimation
            enableFlex
          >
            {
              selects.map(item => (
                <View key={item.id} className="flex-none flex flex-row items-center gap-[8px] box-border rounded-[28px] bg-theme/6 h-[56px] px-[24px]">
                  <Text className="text-theme text-[28px]">{item.name}</Text>
                  <GpFontIcon name="icon-guanbi" className="text-theme" size={24} onClick={() => handleRemoveSelect(item)}/>
                </View>
              ))
            }
          </ScrollView>
        </View>
        <View className="pt-[16px] px-[32px] pb-[32px] box-border">
          <Button className="w-full h-[80px] flex justify-center items-center rounded-[64px] bg-theme" onClick={handleSave}>
            <Text className="text-white text-[32px]">保存</Text>
          </Button>
        </View>
      </View>
    )
  }
  function renderSelectPannel() {
    const { open, options, pannelSelects } = selectPannelState
    return (
      <Popup open={open} placement="bottom" rounded onClose={handleCloseSelectPannel}>
        <Popup.Backdrop />
        <View className="flex flex-row justify-between items-center px-[32px] pt-[40px] pb-[20px]">
          <Text className="text-primary text-[36px] font-bold">证书等级</Text>
          <GpFontIcon name="icon-guanbi" color="#707275" size={48} onClick={handleCloseSelectPannel} />
        </View>
        <View className="px-[32px] py-[24px] box-border max-h-[400px] overflow-y-auto flex flex-row flex-wrap gap-[24px]">
          {
            options.map(l => (
              <View key={l.item.id} onClick={() => handleTapPannelEntry(l)}
                className={clsx("flex flex-row justify-center items-center h-[80px] box-border px-[20px] rounded-[16px]", pannelSelects.findIndex(m => m.id === l.item.id) === -1 ? "text-primary bg-[#F4F6FC]" : "text-white bg-theme font-bold")}>
                <Text className="text-[28px]">{l.item.name}</Text>
              </View>
            ))
          }
        </View>
        <View className="px-[32px] pb-[32px] pt-[16px] mt-[80px]">
          <Button className="flex flex-row justify-center items-center rounded-[64px] h-[80px] bg-theme text-white text-[32px]" onClick={handleSaveSelectPannel}>
            保存
          </Button>
        </View>
        <SafeArea position="bottom" />
      </Popup>
    )
  }
  return (
    <GpContainer className="bg-white box-border h-screen flex flex-col">
      <View className="px-[32px] pb-[24px] flex flex-col flex-none">
        <View className="flex flex-row justify-between items-center">
          <Text className="text-primary font-bold text-[48px] leading-[48px] pt-[20px]">资质证书</Text>
          <Text className="text-primary text-[36px] font-bold">
            <Text className="text-theme">{selects.length}</Text>
            /{availableCertificates.current.length}
          </Text>
        </View>
        <GpSearchInput
          className="mt-[32px]"
          placeholder="搜索证书名称"
          value={search}
          onChange={handleSearchChange}
        />
      </View>
      { searchList.length > 0 ? renderSearchList() : renderCertificateList() }
      { renderSelectPannel() }
    </GpContainer>
  )
}
